﻿using System;
using System.Diagnostics.Contracts;
using System.Threading;

namespace O1.Kernel.Storage.Transactions
{
    [ContractVerification(true)]
    public struct MultiContainer<T> : IEquatable<MultiContainer<T>> 
    {
        internal MultiVersion<T>[] Ptr;

        public bool Equals(MultiContainer<T> other)
        {
            return ReferenceEquals(this.Ptr, other.Ptr);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2231:OverloadOperatorEqualsOnOverridingValueTypeEquals", Justification = "TODO later...")]
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (!(obj is MultiContainer<T>))
            {
                return false;            
            }

            return this.Equals((MultiContainer<T>)obj);
        }

        public override int GetHashCode()
        {
            if (this.Ptr == null)
            {
                return 0;
            }

            return this.Ptr.GetHashCode();
        }

        internal long Swap(MultiVersion<T>[] versions, long versionId)
        {
            var current = this.Ptr;
            var owner = versions.PendingOwner(versionId);
            if (owner != versionId)
            {
                return owner;
            }

            if (Interlocked.CompareExchange(ref this.Ptr, versions, current) == current)
            {
                return versionId;
            }

            return versions.PendingOwner(versionId);
        }

        internal bool GCSwap(MultiVersion<T>[] versions)
        {
            // Garbage collection only
            var current = this.Ptr;
            if (Interlocked.CompareExchange(ref this.Ptr, versions, current) == current)
            {
                return true;
            }

            return false;
        }
    }
}